
package com.gitee.jmash.rbac.mapper;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import com.crenjoy.proto.mapper.BeanMapper;
import com.crenjoy.proto.mapper.ProtoMapper;
import com.gitee.jmash.common.tree.Node;
import com.gitee.jmash.common.tree.Tree;
import com.gitee.jmash.core.orm.DtoPage;
import com.gitee.jmash.core.orm.DtoTotal;
import com.gitee.jmash.rbac.entity.ResourceEntity;
import com.gitee.jmash.rbac.model.TreeResult;
import jmash.protobuf.TreeModel;
import jmash.rbac.protobuf.Menu;
import jmash.rbac.protobuf.MenuList;
import jmash.rbac.protobuf.MenuMeta;
import jmash.rbac.protobuf.ResourceCreateReq;
import jmash.rbac.protobuf.ResourceList;
import jmash.rbac.protobuf.ResourceModel;
import jmash.rbac.protobuf.ResourcePage;
import jmash.rbac.protobuf.ResourceType;
import jmash.rbac.protobuf.ResourceUpdateReq;

/**
 * ResourceMapper.
 *
 * @author <a href="mailto:service@crenjoy.com">crenjoy</a>
 */
@Mapper
public interface ResourceMapper extends BeanMapper, ProtoMapper {

  ResourceMapper INSTANCE = Mappers.getMapper(ResourceMapper.class);

  /** 资源转Menu. */
  default Menu.Builder modelMenu(ResourceEntity resource) {
    Menu.Builder builder = Menu.newBuilder();
    builder.setPath(resource.getUrl());
    MenuMeta.Builder meta = MenuMeta.newBuilder();
    meta.setTitle(resource.getResourceName());
    meta.setIcon(resource.getIcon());
    meta.setHidden(resource.getHidden());
    meta.setKeepAlive(resource.getKeepAlive());
    builder.setMeta(meta);
    return builder;
  }



  default MenuList listMenu(Tree<ResourceEntity, UUID> tree) {
    // 全部资源模型.
    Map<UUID, Menu.Builder> map =
        tree.getAllList().stream().collect(Collectors.toMap(ResourceEntity::getResourceId,
            obj -> ResourceMapper.INSTANCE.modelMenu(obj), (oldValue, newValue) -> oldValue));

    // 倒序添加孩子
    List<ResourceEntity> reverseList = new ArrayList<>(tree.getAllList());
    Collections.reverse(reverseList);

    // 数据建立父子关系
    List<UUID> roots = new ArrayList<>();
    for (ResourceEntity resource : reverseList) {
      Menu.Builder model = map.get(resource.getResourceId());
      Menu.Builder parent = map.get(resource.getParentId());
      Node<ResourceEntity, UUID> node = tree.getNode(resource.getResourceId());
      if (ResourceType.catalog.equals(node.getEntity().getResourceType())) {
        if (!node.isRoot() && node.getParent().isRoot()) {
          model.setComponentName("Layout");
        }
        model.setRedirect(redirectUrl(node, ""));
      } else {
        model.setRedirect("");
        model.setComponentName(getComponentName(node, ""));
      }

      if (parent == null) {
        roots.add(resource.getResourceId());
      } else {
        parent.addChildren(0, model.build());
      }
    }
    // 根列表
    MenuList.Builder builder = MenuList.newBuilder();
    for (UUID root : roots) {
      builder.addMenus(0, map.get(root));
    }
    return builder.build();
  }

  /** 生成前端路由redirect. */
  default String redirectUrl(Node<ResourceEntity, UUID> node, final String path) {
    if (node.isLeaf() && StringUtils.isEmpty(path)) {
      return "";
    }
    String newPath = path + (path.endsWith("/") ? "" : "/") + node.getEntity().getUrl();
    if (node.getEntity().getUrl().startsWith("/")) {
      newPath = node.getEntity().getUrl();
    }
    if (node.isLeaf()) {
      return newPath;
    }
    return redirectUrl(node.getChilds().get(0), newPath);
  }

  /** 生成前端路由组件名称. */
  default String getComponentName(Node<ResourceEntity, UUID> node, final String path) {
    if (node.isRoot()) {
      return path;
    }
    String newPath = "";
    String split = (node.getEntity().getUrl().endsWith("/") ? "" : "/");
    if (StringUtils.isBlank(path)) {
      newPath = node.getEntity().getUrl() + split + "index";
    } else {
      newPath = node.getEntity().getUrl() + split + path;
    }
    // 根地址开始路径.
    if (newPath.startsWith("/")) {
      return newPath;
    }
    return getComponentName(node.getParent(), newPath);
  }

  default ResourceList listResource(List<ResourceEntity> list) {
    // 全部资源模型.
    Map<UUID, ResourceModel.Builder> map = list.stream()
        .collect(Collectors.toMap(ResourceEntity::getResourceId,
            obj -> ResourceMapper.INSTANCE.model(obj).toBuilder(),
            (oldValue, newValue) -> oldValue));
    // 倒序添加孩子
    List<ResourceEntity> reverseList = new ArrayList<>(list);
    Collections.reverse(reverseList);

    // 数据建立父子关系
    List<UUID> roots = new ArrayList<>();
    for (ResourceEntity resource : reverseList) {
      ResourceModel.Builder model = map.get(resource.getResourceId());
      ResourceModel.Builder parent = map.get(resource.getParentId());
      if (parent == null) {
        roots.add(resource.getResourceId());
      } else {
        parent.addChildren(0, model);
      }
    }
    // 根列表
    ResourceList.Builder builder = ResourceList.newBuilder();
    for (UUID root : roots) {
      builder.addResults(0, map.get(root));
    }
    return builder.build();
  }

  ResourcePage pageResource(DtoPage<ResourceEntity, DtoTotal> page);

  default ResourceModel modelPerms(ResourceEntity entity, List<String> perms) {
    ResourceModel model = this.model(entity);
    if (perms != null && perms.size() > 0) {
      model = model.toBuilder().addAllOperCodes(perms).build();
    }
    return model;
  }

  ResourceModel model(ResourceEntity entity);

  TreeModel treeModel(TreeResult entity);

  ResourceEntity create(ResourceCreateReq req);

  ResourceEntity clone(ResourceEntity entity);
  
  ResourceCreateReq genCreate(ResourceModel entity);

  ResourceUpdateReq genUpdate(ResourceModel entity);


}
